#include "input/mouse.h"
#include "core/event.h"
#include "core/log.h"

namespace input {
	Mouse::Mouse() {
		core::EventChannel chan;

		chan.add<MouseMoved>(*this);

		chan.add<MouseLeftButtonPressed>(*this);
		chan.add<MouseMiddleButtonPressed>(*this);
		chan.add<MouseRightButtonPressed>(*this);

		chan.add<MouseLeftButtonReleased>(*this);
		chan.add<MouseMiddleButtonReleased>(*this);
		chan.add<MouseRightButtonReleased>(*this);

		chan.add<MouseWheel>(*this);

		for (int i = 0; i < 3; ++i)
			mButtonPressed[i] = false;

		mWheel = 0;
	}

	Mouse::~Mouse() {
	}

	void Mouse::glfwMousePosCallback(int x, int y) {
		static core::EventChannel chan;

		chan.broadcast(MouseMoved(x, y));
	}

	void Mouse::glfwMouseButtonCallback(int button, int state) {
		static core::EventChannel chan;

		switch (button) {
		case GLFW_MOUSE_BUTTON_LEFT:
			switch (state) {
			case GLFW_PRESS:
				chan.broadcast(MouseLeftButtonPressed());
				break;

			case GLFW_RELEASE:
				chan.broadcast(MouseLeftButtonReleased());
				break;

			default:
				gLog << "Mouse: unhandled button state: " << state;
				break;
			}
			break;

		case GLFW_MOUSE_BUTTON_MIDDLE:
			switch (state) {
			case GLFW_PRESS:
				chan.broadcast(MouseMiddleButtonPressed());
				break;

			case GLFW_RELEASE:
				chan.broadcast(MouseMiddleButtonReleased());
				break;

			default:
				gLog << "Mouse: unhandled button state: " << state;
				break;
			}
			break;

		case GLFW_MOUSE_BUTTON_RIGHT:
			switch (state) {
			case GLFW_PRESS:
				chan.broadcast(MouseRightButtonPressed());
				break;

			case GLFW_RELEASE:
				chan.broadcast(MouseRightButtonReleased());
				break;

			default:
				gLog << "Mouse: unhandled button state: " << state;
				break;
			}
			break;

		default:
			gLog << "Mouse: unhandled button type: " << button;
		}
	}

	void Mouse::glfwMouseWheelCallback(int value) {
		static core::EventChannel chan;

		chan.broadcast(MouseWheel(value));
	}

	Mouse::MouseMoved::MouseMoved(int x, int y): mX(x), mY(y) {}
	Mouse::MouseWheel::MouseWheel(int value): mValue(value) {}

	void Mouse::handle(const Mouse::MouseMoved& mm) {
		mX = mm.mX;
		mY = mm.mY;
	}

	void Mouse::handle(const Mouse::MouseLeftButtonPressed&) {
		mButtonPressed[LEFT_BUTTON] = true;
	}

	void Mouse::handle(const Mouse::MouseMiddleButtonPressed&) {
		mButtonPressed[MIDDLE_BUTTON] = true;
	}

	void Mouse::handle(const Mouse::MouseRightButtonPressed&) {
		mButtonPressed[RIGHT_BUTTON] = true;
	}

	void Mouse::handle(const Mouse::MouseLeftButtonReleased&) {
		mButtonPressed[LEFT_BUTTON] = false;
	}
	
	void Mouse::handle(const Mouse::MouseMiddleButtonReleased&) {
		mButtonPressed[MIDDLE_BUTTON] = false;
	}

	void Mouse::handle(const Mouse::MouseRightButtonReleased&) {
		mButtonPressed[RIGHT_BUTTON] = false;
	}

	void Mouse::handle(const Mouse::MouseWheel& mw) {
		mWheel = mw.mValue;
	}
}